﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using Microsoft.Win32;
using RWLib;
using Action = RWLib.Action;

namespace RW_GUI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Properties
        private List<Fluent> _fluents = new List<Fluent>();
        private List<ActionModel> _actions = new List<ActionModel>();
        private List<ScenarioModel> _scenarios = new List<ScenarioModel>();
        private List<QueryModel> _queries = new List<QueryModel>();
        private List<FormulaModel> _initialConditions = new List<FormulaModel>();
        private TreeViewItem _fluentNode, _actionNode, _scenarioNode, _queryNode, _initialConditionsNode;
        private Timeline.Node _root;
        private Action shoot, load, hide, shoot2, shoot3;
        private double _height, _width;
        private string str;
        private bool LoadedFromFile;

        #endregion
        public MainWindow()
        {
            InitializeComponent();
            var sc = new Scenario(new List<List<Action>> { new List<Action> { load }, new List<Action> { shoot, shoot2, shoot3 } },
            new List<Fluent> { { new Fluent("Alive", true) }, new Fluent("Hidden", false), new Fluent("Loaded", false) });
            var t = new Timeline();
            //_root = t.Run(sc);
            DrawTree();
            _height = Map.Height;
            _width = Map.Width;
        }
        private void btn_AddFluent_Click(object sender, RoutedEventArgs e)
        {
            var afw = new AddFluentWindow();
            afw.ShowDialog();
            if (!afw.valid) return;
            if (_fluents.Exists(x => x.Name.Equals(afw.name)))
            {
                MessageBox.Show("Fluent already saved");
                return;
            }
            _fluents.Add(new Fluent(afw.name));
            Tree.UpdateLayout();
            DrawTextContent();
            DrawTree();
        }
        private void DrawTree()
        {
            Tree.Items.Clear();
            _fluentNode = new TreeViewItem { Header = "Fluents" };
            foreach (var fluentnode in _fluents.Select(x => new TreeViewItem { Header = x.Name }))
            {
                fluentnode.MouseDoubleClick += OnItemMouseDoubleClick;
                _fluentNode.Items.Add(fluentnode);
            }

            _initialConditionsNode = new TreeViewItem { Header = "Initial conditions" };
            foreach (var initialCondition in _initialConditions.Select(x => new TreeViewItem { Header = x.Formula }))
            {
                initialCondition.MouseDoubleClick += OnItemMouseDoubleClick;
                _initialConditionsNode.Items.Add(initialCondition);
            }

            _actionNode = new TreeViewItem { Header = "Actions" };
            foreach (var actionnode in _actions.Select(action => new TreeViewItem { Header = action.ToString() }))
            {
                actionnode.MouseDoubleClick += OnItemMouseDoubleClick;
                _actionNode.Items.Add(actionnode);
            }
            _queryNode = new TreeViewItem { Header = "Queries" };
            foreach (var querynode in _queries.Select(query => new TreeViewItem { Header = query.ToString() }))
            {
                querynode.MouseDoubleClick += OnItemMouseDoubleClick;
                _queryNode.Items.Add(querynode);
            }

            _scenarioNode = new TreeViewItem { Header = "Scenario" };
            foreach (var scenarionode in _scenarios.Select(scenario => new TreeViewItem { Header = scenario.ToString() }))
            {
                scenarionode.MouseDoubleClick += OnItemMouseDoubleClick;
                _scenarioNode.Items.Add(scenarionode);
            }

            Tree.Items.Add(_fluentNode);
            Tree.Items.Add(_initialConditionsNode);
            Tree.Items.Add(_actionNode);
            Tree.Items.Add(_queryNode);
            Tree.Items.Add(_scenarioNode);
            Tree.Items.Refresh();
            foreach (var item in Tree.Items)
            {
                ((TreeViewItem)item).ExpandSubtree();
            }
            Tree.UpdateLayout();
        }
        private void btn_AddAction_Click(object sender, RoutedEventArgs e)
        {
            if (!LoadedFromFile && !_fluents.Any())
            {
                MessageBox.Show("There are no fluents yet!");
                return;
            }
            var aaw = new AddActionWindow(_fluents, _actions);
            aaw.ShowDialog();
            if (aaw.valid)
            {
                _actions.Add(aaw.Model);
            }
            Tree.UpdateLayout();
            DrawTextContent();
            DrawTree();
        }
        private void btn_AddScenario_Click(object sender, RoutedEventArgs e)
        {
            if (!LoadedFromFile && !_actions.Any())
            {
                MessageBox.Show("There are no actions yet!");
                return;
            }
            var asw = new AddScenarioWindow(_actions);
            asw.ShowDialog();
            if (asw.isValid)
            {
                _scenarios.Add(asw.Model);
            }
            Tree.UpdateLayout();
            DrawTextContent();
            DrawTree();
        }
        private void TraverseNode(Node node, Point p, int time)
        {
            if (node == null) return;
            var rec = new Rectangle { Width = 30, Height = _height, Fill = Brushes.Blue };
            Canvas.SetTop(rec, -500);
            Canvas.SetLeft(rec, p.X - 15);
            //Canvas.SetZIndex(rec, 0);
            if (time % 2 == 0 && !Map.Children.Contains(rec))
                Map.Children.Add(rec);
            var ellipse = DrawNode(p);
            var sb = new StringBuilder();
            if (time != 0)
            {
                sb.Append("T=" + (time-1));
                foreach (var fluent in node.Fluents)
                {
                    var value = fluent.Value ?? false;
                    sb.Append(Environment.NewLine + (value ? "" : "~") + fluent.Name);
                }
                foreach (var action in node.actions)
                {
                    sb.Append(Environment.NewLine + action.Name);
                }
            }
            else
                sb.Append("Tree");
            ellipse.ToolTip = new ToolTip { Content = sb.ToString() };
            //Canvas.SetZIndex(ellipse, 2);
            Map.Children.Add(ellipse);
            var x = p.X + 30;
            var y = p.Y;
            var j = Math.Round((double)(node.Nodes.Count / 2));
            for (var i = 0; i < node.Nodes.Count; i++)
            {
                var child = node.Nodes[i];
                var point = new Point(x, y + (i - j) * 30);
                var line = new Line { X1 = p.X, Y1 = p.Y, X2 = point.X, Y2 = point.Y, StrokeThickness = 2, Stroke = Brushes.Black };
                //Canvas.SetZIndex(line, 2);
                Map.Children.Add(line);
                TraverseNode(child, point, time + 1);
            }
        }
        private void Run_Click(object sender, RoutedEventArgs e)
        {
            var parser = new Parser();
            var sc = new SortedDictionary<int, List<string>>();
            TB_Answers.Text = "";
            var splits = TB_Content.Text.Split(new[] { "Actions", "Scenarios", "Queries" }, StringSplitOptions.None);
            if (!splits.Any() || splits.Count() == 1)
                return;
            var fluents = splits[0].Trim();
            var actions = splits[1].Trim();
            var queries = splits[2].Trim();
            var scenario = splits[3].Trim();


            var statements = String.Concat(String.Concat(fluents, "\n"), actions);
            parser.Parse(statements);
            if (!parser.ErrorMessage.Equals(String.Empty))
            {
                MessageBox.Show(parser.ErrorMessage);
                return;
            }
            var scenarioObject = parser.ParseScenario(scenario);
            if (!parser.ErrorMessage.Equals(String.Empty))
            {
                MessageBox.Show(parser.ErrorMessage);
                return;
            }
            var tree = parser.BuildTree(scenarioObject);
            if (!parser.ErrorMessage.Equals(String.Empty))
            {
                MessageBox.Show(parser.ErrorMessage);
                return;
            }
            if (!String.IsNullOrEmpty(queries))
            {
                var answers = parser.ParseQueries(tree, queries);
                if (!parser.ErrorMessage.Equals(String.Empty))
                {
                    MessageBox.Show(parser.ErrorMessage);
                    return;
                }
                if (answers != null)
                {
                    foreach (var a in answers)
                    {
                        TB_Answers.Text += a.Key + " " + a.Value + "\n";
                    }
                }
            }

            Map.Children.Clear();
            TraverseNode(tree.Root, new Point(10, _height / 2), 0);
        }
        private Ellipse DrawNode(Point position)
        {
            var ellipse = new Ellipse();
            var solidColorBrush = new SolidColorBrush { Color = Colors.Black };
            ellipse.Fill = solidColorBrush;
            ellipse.Width = 10;
            ellipse.Height = 10;
            Canvas.SetLeft(ellipse, position.X - 5);
            Canvas.SetTop(ellipse, position.Y - 5);
            return ellipse;
        }
        private void DrawTextContent()
        {
            var sb = new StringBuilder();

            //"initially not loadedR and not loadedL and not hidden and alive" 
            if (_fluents.Any() && !LoadedFromFile)
            {
                sb.Append("Fluents:");
                for (var index = 0; index < _fluents.Count; index++)
                {
                    var fluent = _fluents[index];
                    sb.Append(" " + fluent.Name);
                    if (index == _fluents.Count - 1) break;
                    sb.Append(" ,");
                }
            }
            sb.AppendLine();
            sb.Append("Initially");
            if (_initialConditions.Any())
            {
                for (var index = 0; index < _initialConditions.Count; index++)
                {
                    var initialCondition = _initialConditions[index];
                    sb.Append(" " + initialCondition.Formula);
                    if (index == _initialConditions.Count - 1) break;
                    sb.Append(" and");
                }
            }
            sb.AppendLine();
            sb.AppendLine("Actions");
            if (_actions.Any() && !LoadedFromFile)
            {
                foreach (var action in _actions)
                {
                    sb.AppendLine(action.ToString());
                }
            }
            sb.AppendLine("Queries");
            sb.AppendLine();
            if (_queries.Any() && !LoadedFromFile)
            {
                foreach (var query in _queries)
                {
                    sb.AppendLine(query.ToString());
                }
            }
            sb.AppendLine("Scenarios");
            sb.AppendLine();
            if (_scenarios.Any())
            {
                foreach (var scenario in _scenarios)
                {
                    sb.AppendLine(scenario.ToString());
                }
            }

            TB_Content.Text = sb.ToString();
        }
        private void ButtonLoadFileClick(object sender, RoutedEventArgs e)
        {
            var ofd = new OpenFileDialog();
            ofd.ShowDialog();
            if (String.IsNullOrEmpty(ofd.FileName.Trim()))
            {
                return;
            }
            var filestream = new StreamReader(ofd.FileName);
            str = filestream.ReadToEnd();
            LoadedFromFile = true;

            if (!str.Trim().Equals(String.Empty))
            {
                btn_AddAction.IsEnabled = false;
                btn_AddFluent.IsEnabled = false;
                btn_AddScenario.IsEnabled = false;
                btn_AddQuery.IsEnabled = false;

                var splits = str.Split(new[] { "Actions", "Scenarios", "Queries" }, StringSplitOptions.None);
                if (splits.Count() != 4)
                {
                    MessageBox.Show("The file must contain initial fluents, actions, queries and scenarios");
                    return;
                }
                var fluents = splits[0].Trim();
                var actions = splits[1].Trim();
                var queries = splits[2].Trim();
                var scenario = splits[3].Trim();


                var parser = new Parser();
                var statements = String.Concat(String.Concat(fluents, "\n"), actions);
                parser.Parse(statements);
                if (!parser.ErrorMessage.Equals(String.Empty))
                {
                    MessageBox.Show(parser.ErrorMessage);
                    return;
                }

                parser.ParseScenario(scenario);
                if (!parser.ErrorMessage.Equals(String.Empty))
                {
                    MessageBox.Show(parser.ErrorMessage);
                    return;
                }
                var tree = parser.BuildTree(parser.ScenarioFromText);
                if (!parser.ErrorMessage.Equals(String.Empty))
                {
                    MessageBox.Show(parser.ErrorMessage);
                    return;
                }
                var answers = parser.ParseQueries(tree, queries);
                if (!parser.ErrorMessage.Equals(String.Empty))
                {
                    MessageBox.Show(parser.ErrorMessage);
                    return;
                }
                BtnClearClick(new object(), new RoutedEventArgs());
                if (answers != null)
                {
                    foreach (var a in answers)
                    {
                        TB_Answers.Text += a.Key + " " + a.Value + "\n";
                    }
                }

                Map.Children.Clear();
                TraverseNode(tree.Root, new Point(10, _height / 2), 0);
            }
            TB_Content.Text = str;
        }
        private void OnItemMouseDoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
        {
            var treeViewItem = Tree.SelectedItem as TreeViewItem;
            if (treeViewItem == null || treeViewItem.Header.Equals("Actions") || treeViewItem.Header.Equals("Fluents")) return;
            if (_actionNode.Items.Contains(treeViewItem))
            {
                for (var i = 0; i < _actions.Count; i++)
                {
                    var action = _actions[i];
                    if (!action.ToString().Equals(treeViewItem.Header)) continue;
                    _actions.RemoveAt(i);
                    DrawTextContent();
                    DrawTree();
                    return;
                }
            }
            else if (_fluentNode.Items.Contains(treeViewItem))
            {
                for (var i = 0; i < _fluents.Count; i++)
                {
                    var fluent = _fluents[i];
                    if (!fluent.ToString().Equals(treeViewItem.Header)) continue;
                    _fluents.RemoveAt(i);
                    DrawTextContent();
                    DrawTree();
                    return;
                }
            }
            else if (_initialConditionsNode.Items.Contains(treeViewItem))
            {
                for (var i = 0; i < _initialConditions.Count; i++)
                {
                    var initialcondition = _initialConditions[i];
                    if (!initialcondition.ToString().Equals(treeViewItem.Header)) continue;
                    _initialConditions.RemoveAt(i);
                    DrawTextContent();
                    DrawTree();
                    return;
                }
            }
            else if (_scenarioNode.Items.Contains(treeViewItem))
            {
                for (var i = 0; i < _scenarios.Count; i++)
                {
                    var scenario = _scenarios[i];
                    if (!scenario.ToString().Equals(treeViewItem.Header)) continue;
                    _scenarios.RemoveAt(i);
                    DrawTextContent();
                    DrawTree();
                    return;
                }
            }
            else if (_queryNode.Items.Contains(treeViewItem))
            {
                for (var i = 0; i < _queries.Count; i++)
                {
                    var query = _queries[i];
                    if (!query.ToString().Equals(treeViewItem.Header)) continue;
                    _queries.RemoveAt(i);
                    DrawTextContent();
                    DrawTree();
                    return;
                }
            }
        }
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (!_fluents.Any())
            {
                MessageBox.Show("There are no fluents yet!");
                return;
            }
            var aqw = new AddQueryWindow(_fluents, _actions);
            aqw.ShowDialog();
            if (aqw.Valid)
            {
                _queries.Add(aqw.Model);
            }
            Tree.UpdateLayout();
            DrawTextContent();
            DrawTree();
        }
        private void BtnClearClick(object sender, RoutedEventArgs e)
        {
            btn_AddAction.IsEnabled = true;
            btn_AddFluent.IsEnabled = true;
            btn_AddScenario.IsEnabled = true;
            btn_AddQuery.IsEnabled = true;
            TB_Answers.Text = "";
            TB_Content.Text = "";
            LoadedFromFile = false;
            _actions.Clear();
            _fluents.Clear();
            _scenarios.Clear();
            _queries.Clear();
            _initialConditions.Clear();
            Tree.UpdateLayout();
            DrawTextContent();
            DrawTree();
            Map.Children.Clear();
        }
        private void btn_AddInitialConditions_Click(object sender, RoutedEventArgs e)
        {
            var aic = new AddInitialConditionWindow(_fluents);
            aic.ShowDialog();
            if (!aic.valid)
            {
                return;
            }
            _initialConditions.Add(aic.Model);
            Tree.UpdateLayout();
            DrawTextContent();
            DrawTree();
        }
    }
}